﻿using System;
using System.Diagnostics;
using System.Text;
using System.Collections;
using System.Drawing;

namespace XUCore.Win32
{
    /// <summary>
    ///Windows常用API方法封装
    /// </summary>
    public static class Windows
    {
        /// <summary>
        /// 窗口阴影特效
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        public static void SetWindowShadow(IntPtr hwnd)
        {
            User32.SetClassLong(hwnd, Const.GCL_STYLE, User32.GetClassLong(hwnd, Const.GCL_STYLE) | Const.CS_DropSHADOW);
        }
        /// <summary>
        /// 锁屏
        /// </summary>
        /// <param name="aLock">true:锁屏+关屏;false:禁止鼠标键盘动作+关屏</param>
        public static void LockWorkStation(bool aLock)
        {
            System.Windows.Forms.Form form = new System.Windows.Forms.Form();
            if (aLock)
            {
                // 锁屏+关屏
                User32.LockWorkStation();
                User32.SendMessage(form.Handle, Const.WM_SYSCOMMAND, Const.SC_MONITORPOWER, Const.MonitorPowerOff);
            }
            else
            {
                // 禁止鼠标键盘动作+关屏
                User32.BlockInput(true);
                System.Threading.Thread.Sleep(10);
                User32.SendMessage(form.Handle, Const.WM_SYSCOMMAND, Const.SC_MONITORPOWER, Const.MonitorPowerOff);
                User32.BlockInput(false);
            }
            form.Dispose();
        }

        /// <summary>
        /// 获取窗口标题
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        public static string GetWindowText(IntPtr hwnd)
        {
            StringBuilder stringBuilder = new StringBuilder(1024);
            User32.GetWindowText(hwnd, stringBuilder, 1024);
            return stringBuilder.ToString();
        }
        /// <summary>
        /// 判断窗口举行范围是否存在
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        public static bool IsEmptyWindowRect(IntPtr hwnd)
        {
            RECT rect = new RECT();
            User32.GetWindowRect(hwnd, out rect);
            return (rect.right - rect.left) < 0;

        }
        /// <summary>
        /// 获取窗口句柄类名
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        public static string GetClassName(IntPtr hwnd)
        {
            StringBuilder classname = new StringBuilder(125);
            User32.GetClassName(hwnd, classname, classname.Capacity);
            return classname.ToString();
        }

        /// <summary>
        /// 获取窗口的进程名称
        /// </summary>
        /// <param name="hwnd">窗口句柄，如果hwnd等于IntPtr.Zero，则返回当前组件窗口的进程名称</param>
        /// <returns>进程名称</returns>
        public static string GetWindowProcessName(IntPtr hwnd)
        {
            if (hwnd == IntPtr.Zero)
            {
                hwnd = Win32.User32.GetForegroundWindow();
            }
            hwnd = GetTopWindow(hwnd);
            int pid = 0;
            string ProcessName = "";
            Win32.User32.GetWindowThreadProcessId(hwnd, out pid);
            if (pid > 0)
            {
                Process process = Process.GetProcessById(pid);
                if (process != null)
                { ProcessName = process.ProcessName; }
            }
            return ProcessName;
        }
        /// <summary>
        /// 获取顶层窗口
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        /// <returns>窗口句柄</returns>
        public static IntPtr GetTopWindow(IntPtr hwnd)
        {
            IntPtr phwnd = User32.GetParent(hwnd);
            if (phwnd == IntPtr.Zero) return hwnd;
            return GetTopWindow(phwnd);
        }

        /// <summary>
        /// 置顶窗口并设置焦点
        /// </summary>
        /// <param name="hwnd">窗口句柄</param>
        public static void SetTopFocus(IntPtr hwnd)
        {
            Win32.User32.SetForegroundWindow(hwnd);
            Win32.User32.SetFocus(hwnd);
        }

        private static Hashtable ProcessWnd = null;

        public static IntPtr GetWindowHandleByProcessId(uint processId)
        {
            if (ProcessWnd == null)
            {
                ProcessWnd = new Hashtable();
            }
            IntPtr winHandle = IntPtr.Zero;
            object objWnd = ProcessWnd[processId];
            if (objWnd != null)
            {
                winHandle = (IntPtr)objWnd;
                if (winHandle != IntPtr.Zero && Win32.User32.IsWindow(winHandle))
                {
                    return winHandle;
                }
                else
                    winHandle = IntPtr.Zero;
            }
            bool result = Win32.User32.EnumWindows(new User32.WNDENUMPROC(EnumWindowsProc), processId);
            if (!result)
            {
                objWnd = ProcessWnd[processId];
                if (objWnd != null)
                {
                    winHandle = (IntPtr)objWnd;
                }
            }
            return winHandle;

        }

        public static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
        {
            uint uiPid = 0;
            if (Win32.User32.GetParent(hwnd) == IntPtr.Zero)
            {
                Win32.User32.GetWindowThreadProcessId(hwnd, out uiPid);
                if (uiPid == lParam)
                {
                    ProcessWnd[uiPid] = hwnd;
                    return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 利用Accessible获取对应坐标的窗口句柄
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static IntPtr GetWindowByPoint(int x, int y)
        {
            IntPtr hwnd = IntPtr.Zero;
            Accessibility.IAccessible accessible;
            object childid;
            Win32.Oleacc.AccessibleObjectFromPoint(new POINT(x, y), out accessible, out childid);
            if (accessible != null)
            {
                Win32.Oleacc.WindowFromAccessibleObject(accessible, ref hwnd);
            }
            return hwnd;
        }

        #region 窗口操作
        /// <summary>
        /// 窗口最大化
        /// </summary>
        /// <param name="hwnd"></param>
        public static void Maximize(IntPtr hwnd)
        {
            User32.ShowWindow(hwnd, Win32.Const.SW_MAXIMIZE);
        }
        /// <summary>
        /// 窗口最小化
        /// </summary>
        /// <param name="hwnd"></param>
        public static void Minimize(IntPtr hwnd)
        {
            User32.ShowWindow(hwnd, Win32.Const.SW_MINIMIZE);
        }
        /// <summary>
        /// 还原窗口
        /// </summary>
        /// <param name="hwnd"></param>
        public static void Normal(IntPtr hwnd)
        {
            User32.ShowWindow(hwnd, Win32.Const.SW_NORMAL);
        }
        /// <summary>
        /// 恢复窗口
        /// </summary>
        /// <param name="hwnd"></param>
        public static void Restore(IntPtr hwnd)
        {
            User32.ShowWindow(hwnd, Win32.Const.SW_RESTORE);
        }
        /// <summary>
        /// 显示窗口
        /// </summary>
        /// <param name="hwnd"></param>
        public static void Show(IntPtr hwnd)
        {
            User32.ShowWindow(hwnd, Win32.Const.SW_SHOW);
        }
        /// <summary>
        /// 隐藏窗口
        /// </summary>
        /// <param name="hwnd"></param>
        public static void Hide(IntPtr hwnd)
        {
            User32.ShowWindow(hwnd, Win32.Const.SW_HIDE);
        }
        /// <summary>
        /// 关闭窗口
        /// </summary>
        /// <param name="hwnd"></param>
        public static void Close(IntPtr hwnd)
        {
            User32.PostMessage((int)hwnd, Win32.Const.WM_CLOSE, IntPtr.Zero, IntPtr.Zero);
        }

        #endregion

        #region ComboBox操作

        /// <summary>
        /// 设置ComboBoxList的选择项，并处触发SelectChange事件通知
        /// </summary>
        /// <param name="handler">当前需要操作的句柄</param>
        /// <param name="index">当前索引</param>
        /// <returns></returns>
        public static void SetComboBoxSelectItem(this IntPtr handler, int index)
        {
            //获取list的父级窗体
            var parentHandler = User32.GetParent(handler);
            // 下选框内容更改
            // 参数：下选框句柄； 消息内容； 参数下选框的哪一个item，以0起始的待选选项的索引；如果该值为-1，将从组合框列表中删除当前选项，并使当前选项为空； 参数
            // CB_Handle为下选框句柄，PCB_handle下选框父窗口句柄
            User32.SendMessage(handler, Const.LB_SETCURSEL, index, 0);
            // 下选框的父窗口命令
            // 参数：父窗口句柄； 命令； 参数：WParam：高位表示类型，低位表示内容；参数IParam，下选框句柄
            // CBN_SELENDOK 当用户选择了有效的列表项时发送，提示父窗体处理用户的选择。 LOWORD为组合框的ID. HIWORD为CBN_SELENDOK的值。
            User32.SendMessage(parentHandler, Const.WM_COMMAND, Const.CBN_SELENDOK, handler.ToInt32());
            // CBN_SELCHANGE 当用户更改了列表项的选择时发送，不论用户是通过鼠标选择或是通过方向键选择都会发送此通知。LOWORD为组合框的ID. HIWORD为CBN_SELCHANGE的值。
            User32.SendMessage(parentHandler, Const.WM_COMMAND, Const.CBN_SELCHANGE, handler.ToInt32());
        }
        /// <summary>
        /// 获取ComboBoxList的选择项的Text值
        /// </summary>
        /// <param name="handler"></param>
        /// <param name="index"></param>
        /// <returns></returns>
        public static string GetComboBoxSelectItemText(this IntPtr handler, int index)
        {
            var name = new StringBuilder();

            User32.SendMessage(handler, Const.LB_GETTEXT, index, name);

            return name.ToString();
        }
        /// <summary>
        /// 获取ComboBoxList的长度
        /// </summary>
        /// <param name="handler"></param>
        /// <returns></returns>
        public static int GetComboBoxCount(this IntPtr handler)
        {
            //定位下拉框ComboBoxlist
            return User32.SendMessage(handler, Const.LB_GETCOUNT, 0, 0);
        }

        #endregion

        #region 鼠标操作

        /// <summary>
        /// 触发鼠标点击事件
        /// </summary>
        /// <param name="handler"></param>
        public static void Click(this IntPtr handler)
        {
            User32.SendMessage(handler, Const.WM_LBUTTONDOWN, 0, 0);
            User32.SendMessage(handler, Const.WM_LBUTTONUP, 0, 0);
        }

        #endregion

        #region 写入和获取对象数据

        /// <summary>
        /// 写入文本
        /// </summary>
        /// <param name="handler"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        public static bool SetText(this IntPtr handler, string text)
        {
            return User32.SendMessage(handler, Const.WM_SETTEXT, 0, new StringBuilder(text));
        }
        /// <summary>
        /// 获取文本
        /// </summary>
        /// <param name="handler"></param>
        /// <returns></returns>
        public static string GetText(this IntPtr handler)
        {
            var text = new StringBuilder();

            User32.SendMessage(handler, Const.WM_GETTEXT, 0, text);

            return text.ToString();
        }

        #endregion

        #region 查找元素

        /// <summary>
        /// 查找窗体
        /// </summary>
        /// <param name="lpClassName"></param>
        /// <param name="lpWindowName"></param>
        /// <returns></returns>
        public static IntPtr FindMainWindow(string lpClassName, string lpWindowName)
        {
            return User32.FindWindow(lpClassName, lpWindowName);
        }
        /// <summary>
        /// 查找子窗体
        /// </summary>
        /// <param name="hwndParent"></param>
        /// <param name="hwndChildAfter"></param>
        /// <param name="lpszClass"></param>
        /// <param name="lpszWindow"></param>
        /// <returns></returns>
        public static IntPtr FindChild(this IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow)
        {
            return User32.FindWindowEx(hwndParent, hwndChildAfter, lpszClass, lpszWindow);
        }

        #endregion

        /// <summary>
        /// 窗体截图
        /// </summary>
        /// <param name="handler"></param>
        /// <returns></returns>
        public static Bitmap PrintWindow(this IntPtr handler)
        {
            IntPtr hscrdc = User32.GetWindowDC(handler);
            User32.GetWindowRect(handler, out var rect);
            IntPtr hbitmap = Gdi32.CreateCompatibleBitmap(hscrdc, rect.right - rect.left, rect.bottom - rect.top);
            IntPtr hmemdc = Gdi32.CreateCompatibleDC(hscrdc);
            Gdi32.SelectObject(hmemdc, hbitmap);
            Gdi32.PrintWindow(handler, hmemdc, 0);
            Bitmap bmp = Bitmap.FromHbitmap(hbitmap);
            Gdi32.DeleteDC(hscrdc);
            Gdi32.DeleteDC(hmemdc);
            return bmp;
        }

    }
}
